home *** CD-ROM | disk | FTP | other *** search
/ Aminet 48 / Aminet 48 (2002)(GTI - Schatztruhe)[!][Apr 2002].iso / Aminet / text / edit / vim60src.lha / Vim / vim60 / src / termlib.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-07-11  |  13.7 KB  |  625 lines

  1. /* vi:set ts=8 sts=4 sw=4: */
  2. /*
  3.  * The following software is (C) 1984 Peter da Silva, the Mad Australian, in
  4.  * the public domain. It may be re-distributed for any purpose with the
  5.  * inclusion of this notice.
  6.  */
  7.  
  8. /* Modified by Bram Moolenaar for use with VIM - Vi Improved. */
  9. /* A few bugs removed by Olaf 'Rhialto' Seibert. */
  10.  
  11. /* TERMLIB: Terminal independant database. */
  12.  
  13. #include "vim.h"
  14. #include "termlib.pro"
  15.  
  16. #if !defined(AMIGA) && !defined(VMS) && !defined(MACOS) && !defined(RISCOS)
  17. # include <sgtty.h>
  18. #endif
  19.  
  20. static int  getent __ARGS((char *, char *, FILE *, int));
  21. static int  nextent __ARGS((char *, FILE *, int));
  22. static int  _match __ARGS((char *, char *));
  23. static char *_addfmt __ARGS((char *, char *, int));
  24. static char *_find __ARGS((char *, char *));
  25.  
  26. /*
  27.  * Global variables for termlib
  28.  */
  29.  
  30. char    *tent;              /* Pointer to terminal entry, set by tgetent */
  31. char    PC = 0;              /* Pad character, default NULL */
  32. char    *UP = 0, *BC = 0;     /* Pointers to UP and BC strings from database */
  33. short    ospeed;              /* Baud rate (1-16, 1=300, 16=19200), as in stty */
  34.  
  35. /*
  36.  * Module: tgetent
  37.  *
  38.  * Purpose: Get termcap entry for <term> into buffer at <tbuf>.
  39.  *
  40.  * Calling conventions: char tbuf[TBUFSZ+], term=canonical name for terminal.
  41.  *
  42.  * Returned values: 1 = success, -1 = can't open file,
  43.  *        0 = can't find terminal.
  44.  *
  45.  * Notes:
  46.  * - Should probably supply static buffer.
  47.  * - Uses environment variables "TERM" and "TERMCAP". If TERM = term (that is,
  48.  *   if the argument matches the environment) then it looks at TERMCAP.
  49.  * - If TERMCAP begins with a slash, then it assumes this is the file to
  50.  *   search rather than /etc/termcap.
  51.  * - If TERMCAP does not begin with a slash, and it matches TERM, then this is
  52.  *   used as the entry.
  53.  * - This could be simplified considerably for non-UNIX systems.
  54.  */
  55.  
  56. #ifndef TERMCAPFILE
  57. # ifdef AMIGA
  58. #  define TERMCAPFILE "s:termcap"
  59. # else
  60. #  ifdef VMS
  61. #   define TERMCAPFILE "VIMRUNTIME:termcap"
  62. #  else
  63. #   define TERMCAPFILE "/etc/termcap"
  64. #  endif
  65. # endif
  66. #endif
  67.  
  68. tgetent(tbuf, term)
  69.     char    *tbuf;        /* Buffer to hold termcap entry, TBUFSZ bytes max */
  70.     char    *term;        /* Name of terminal */
  71. {
  72.     char    tcbuf[32];        /* Temp buffer to handle */
  73.     char    *tcptr = tcbuf;    /* extended entries */
  74.     char    *tcap = TERMCAPFILE; /* Default termcap file */
  75.     char    *tmp;
  76.     FILE    *termcap;
  77.     int        retval = 0;
  78.     int        len;
  79.  
  80.     if ((tmp = (char *)mch_getenv((char_u *)"TERMCAP")) != NULL)
  81.     {
  82.     if (*tmp == '/')        /* TERMCAP = name of termcap file */
  83.     {
  84.         tcap = tmp ;
  85. #if defined(AMIGA)
  86.         /* Convert /usr/share/lib/termcap to usr:share/lib/termcap */
  87.         tcap++;
  88.         tmp = strchr(tcap, '/');
  89.         if (tmp)
  90.         *tmp = ':';
  91. #endif
  92.     }
  93.     else                /* TERMCAP = termcap entry itself */
  94.     {
  95.         int tlen = strlen(term);
  96.  
  97.         while (*tmp && *tmp != ':')        /* Check if TERM matches */
  98.         {
  99.         char *nexttmp;
  100.  
  101.         while (*tmp == '|')
  102.             tmp++;
  103.         nexttmp  = _find(tmp, ":|");    /* Rhialto */
  104.         if (tmp+tlen == nexttmp && _match(tmp, term) == tlen)
  105.         {
  106.             strcpy(tbuf, tmp);
  107.             tent = tbuf;
  108.             return 1;
  109.         }
  110.         else
  111.             tmp = nexttmp;
  112.         }
  113.     }
  114.     }
  115.     if (!(termcap = mch_fopen(tcap, "r")))
  116.     {
  117.     strcpy(tbuf, tcap);
  118.     return -1;
  119.     }
  120.  
  121.     len = 0;
  122.     while (getent(tbuf + len, term, termcap, TBUFSZ - len))
  123.     {
  124.     tcptr = tcbuf;                /* Rhialto */
  125.     if ((term = tgetstr("tc", &tcptr)))    /* extended entry */
  126.     {
  127.         rewind(termcap);
  128.         len = strlen(tbuf);
  129.     }
  130.     else
  131.     {
  132.         retval = 1;
  133.         tent = tbuf;    /* reset it back to the beginning */
  134.         break;
  135.     }
  136.     }
  137.     fclose(termcap);
  138.     return retval;
  139. }
  140.  
  141.     static int
  142. getent(tbuf, term, termcap, buflen)
  143.     char    *tbuf, *term;
  144.     FILE    *termcap;
  145.     int        buflen;
  146. {
  147.     char    *tptr;
  148.     int        tlen = strlen(term);
  149.  
  150.     while (nextent(tbuf, termcap, buflen))    /* For each possible entry */
  151.     {
  152.     tptr = tbuf;
  153.     while (*tptr && *tptr != ':')        /* : terminates name field */
  154.     {
  155.         char    *nexttptr;
  156.  
  157.         while (*tptr == '|')        /* | seperates names */
  158.         tptr++;
  159.         nexttptr = _find(tptr, ":|");    /* Rhialto */
  160.         if (tptr + tlen == nexttptr &&
  161.         _match(tptr, term) == tlen)    /* FOUND! */
  162.         {
  163.         tent = tbuf;
  164.         return 1;
  165.         }
  166.         else                /* Look for next name */
  167.         tptr = nexttptr;
  168.     }
  169.     }
  170.     return 0;
  171. }
  172.  
  173.     static int
  174. nextent(tbuf, termcap, buflen)        /* Read 1 entry from TERMCAP file */
  175.     char    *tbuf;
  176.     FILE    *termcap;
  177.     int        buflen;
  178. {
  179.     char *lbuf = tbuf;                /* lbuf=line buffer */
  180.                 /* read lines straight into buffer */
  181.  
  182.     while (lbuf < tbuf+buflen &&        /* There's room and */
  183.       fgets(lbuf, (int)(tbuf+buflen-lbuf), termcap)) /* another line */
  184.     {
  185.     int llen = strlen(lbuf);
  186.  
  187.     if (*lbuf == '#')            /* eat comments */
  188.         continue;
  189.     if (lbuf[-1] == ':' &&            /* and whitespace */
  190.         lbuf[0] == '\t' &&
  191.         lbuf[1] == ':')
  192.     {
  193.         strcpy(lbuf, lbuf+2);
  194.         llen -= 2;
  195.     }
  196.     if (lbuf[llen-2] == '\\')        /* and continuations */
  197.         lbuf += llen-2;
  198.     else
  199.     {
  200.         lbuf[llen-1]=0;            /* no continuation, return */
  201.         return 1;
  202.     }
  203.     }
  204.  
  205.     return 0;                    /* ran into end of file */
  206. }
  207.  
  208. /*
  209.  * Module: tgetflag
  210.  *
  211.  * Purpose: returns flag true or false as to the existence of a given entry.
  212.  * used with 'bs', 'am', etc...
  213.  *
  214.  * Calling conventions: id is the 2 character capability id.
  215.  *
  216.  * Returned values: 1 for success, 0 for failure.
  217.  */
  218.  
  219. tgetflag(id)
  220.     char *id;
  221. {
  222.     char    buf[256], *ptr = buf;
  223.  
  224.     return tgetstr(id, &ptr) ? 1 : 0;
  225. }
  226.  
  227. /*
  228.  * Module: tgetnum
  229.  *
  230.  * Purpose: get numeric value such as 'li' or 'co' from termcap.
  231.  *
  232.  * Calling conventions: id = 2 character id.
  233.  *
  234.  * Returned values: -1 for failure, else numerical value.
  235.  */
  236.  
  237. tgetnum(id)
  238.     char *id;
  239. {
  240.     char *ptr, buf[256];
  241.     ptr = buf;
  242.  
  243.     if (tgetstr(id, &ptr))
  244.     return atoi(buf);
  245.     else
  246.     return 0;
  247. }
  248.  
  249. /*
  250.  * Module: tgetstr
  251.  *
  252.  * Purpose: get terminal capability string from database.
  253.  *
  254.  * Calling conventions: id is the two character capability id.
  255.  *        (*buf) points into a hold buffer for the
  256.  *        id. the capability is copied into the buffer
  257.  *        and (*buf) is advanced to point to the next
  258.  *        free byte in the buffer.
  259.  *
  260.  * Returned values: 0 = no such entry, otherwise returns original
  261.  *        (*buf) (now a pointer to the string).
  262.  *
  263.  * Notes
  264.  *    It also decodes certain escape sequences in the buffer.
  265.  *  they should be obvious from the code:
  266.  *    \E = escape.
  267.  *    \n, \r, \t, \f, \b match the 'c' escapes.
  268.  *    ^x matches control-x (^@...^_).
  269.  *    \nnn matches nnn octal.
  270.  *    \x, where x is anything else, matches x. I differ
  271.  *  from the standard library here, in that I allow ^: to match
  272.  *  :.
  273.  *
  274.  */
  275.  
  276.     char *
  277. tgetstr(id, buf)
  278.     char    *id, **buf;
  279. {
  280.     int        len = strlen(id);
  281.     char    *tmp=tent;
  282.     char    *hold;
  283.     int        i;
  284.  
  285.     do {
  286.     tmp = _find(tmp, ":");            /* For each field */
  287.     while (*tmp == ':')            /* skip empty fields */
  288.         tmp++;
  289.     if (!*tmp)
  290.         break;
  291.  
  292.     if (_match(id, tmp) == len) {
  293.         tmp += len;                /* find '=' '@' or '#' */
  294.         if (*tmp == '@')            /* :xx@: entry for tc */
  295.         return 0;            /* deleted entry */
  296.         hold= *buf;
  297.         while (*++tmp && *tmp != ':') {    /* not at end of field */
  298.         switch(*tmp) {
  299.         case '\\':            /* Expand escapes here */
  300.             switch(*++tmp) {
  301.             case 0:            /* ignore backslashes */
  302.             tmp--;            /* at end of entry */
  303.             break;            /* shouldn't happen */
  304.             case 'e':
  305.             case 'E':            /* ESC */
  306.             *(*buf)++ = ESC;
  307.             break;
  308.             case 'n':            /* \n */
  309.             *(*buf)++ = '\n';
  310.             break;
  311.             case 'r':            /* \r */
  312.             *(*buf)++ = '\r';
  313.             break;
  314.             case 't':            /* \t */
  315.             *(*buf)++ = '\t';
  316.             break;
  317.             case 'b':            /* \b */
  318.             *(*buf)++ = '\b';
  319.             break;
  320.             case 'f':            /* \f */
  321.             *(*buf)++ = '\f';
  322.             break;
  323.             case '0':            /* \nnn */
  324.             case '1':
  325.             case '2':
  326.             case '3':
  327.             case '4':
  328.             case '5':
  329.             case '6':
  330.             case '7':
  331.             case '8':
  332.             case '9':
  333.             **buf = 0;
  334.                 /* get up to three digits */
  335.             for (i = 0; i < 3 && isdigit(*tmp); ++i)
  336.                 **buf = **buf * 8 + *tmp++ - '0';
  337.             (*buf)++;
  338.             tmp--;
  339.             break;
  340.             default:            /* \x, for all other x */
  341.             *(*buf)++= *tmp;
  342.             }
  343.             break;
  344.         case '^':            /* control characters */
  345.             ++tmp;
  346.             *(*buf)++ = Ctrl_chr(*tmp);
  347.             break;
  348.         default:
  349.             *(*buf)++ = *tmp;
  350.         }
  351.         }
  352.         *(*buf)++ = 0;
  353.         return hold;
  354.     }
  355.     } while (*tmp);
  356.  
  357.     return 0;
  358. }
  359.  
  360. /*
  361.  * Module: tgoto
  362.  *
  363.  * Purpose: decode cm cursor motion string.
  364.  *
  365.  * Calling conventions: cm is cursor motion string.  line, col, are the
  366.  * desired destination.
  367.  *
  368.  * Returned values: a string pointing to the decoded string, or "OOPS" if it
  369.  * cannot be decoded.
  370.  *
  371.  * Notes
  372.  *    The accepted escapes are:
  373.  *    %d     as in printf, 0 origin.
  374.  *    %2, %3   like %02d, %03d in printf.
  375.  *    %.     like %c
  376.  *    %+x     adds <x> to value, then %.
  377.  *    %>xy     if value>x, adds y. No output.
  378.  *    %i     increments line& col, no output.
  379.  *    %r     reverses order of line&col. No output.
  380.  *    %%     prints as a single %.
  381.  *    %n     exclusive or row & col with 0140.
  382.  *    %B     BCD, no output.
  383.  *    %D     reverse coding (x-2*(x%16)), no output.
  384.  */
  385.  
  386.     char *
  387. tgoto(cm, col, line)
  388.     char    *cm;                /* cm string, from termcap */
  389.     int col,                    /* column, x position */
  390.     line;                    /* line, y position */
  391. {
  392.     char    gx, gy,                /* x, y */
  393.     *ptr,                    /* pointer in 'cm' */
  394.     reverse = 0,                /* reverse flag */
  395.     *bufp,                    /* pointer in returned string */
  396.     addup = 0,                /* add upline */
  397.     addbak = 0,                /* add backup */
  398.     c;
  399.     static char buffer[32];
  400.  
  401.     if (!cm)
  402.     return "OOPS";                /* Kludge, but standard */
  403.  
  404.     bufp = buffer;
  405.     ptr = cm;
  406.  
  407.     while (*ptr) {
  408.     if ((c = *ptr++) != '%') {        /* normal char */
  409.         *bufp++ = c;
  410.     } else {                /* % escape */
  411.         switch(c = *ptr++) {
  412.         case 'd':                /* decimal */
  413.         bufp = _addfmt(bufp, "%d", line);
  414.         line = col;
  415.         break;
  416.         case '2':                /* 2 digit decimal */
  417.         bufp = _addfmt(bufp, "%02d", line);
  418.         line = col;
  419.         break;
  420.         case '3':                /* 3 digit decimal */
  421.         bufp = _addfmt(bufp, "%03d", line);
  422.         line = col;
  423.         break;
  424.         case '>':                /* %>xy: if >x, add y */
  425.         gx = *ptr++;
  426.         gy = *ptr++;
  427.         if (col>gx) col += gy;
  428.         if (line>gx) line += gy;
  429.         break;
  430.         case '+':                /* %+c: add c */
  431.         line += *ptr++;
  432.         case '.':                /* print x/y */
  433.         if (line == '\t' ||        /* these are */
  434.            line == '\n' ||        /* chars that */
  435.            line == '\004' ||        /* UNIX hates */
  436.            line == '\0') {
  437.             line++;            /* so go to next pos */
  438.             if (reverse == (line == col))
  439.             addup=1;        /* and mark UP */
  440.             else
  441.             addbak=1;        /* or BC */
  442.         }
  443.         *bufp++=line;
  444.         line = col;
  445.         break;
  446.         case 'r':                /* r: reverse */
  447.         gx = line;
  448.         line = col;
  449.         col = gx;
  450.         reverse = 1;
  451.         break;
  452.         case 'i':            /* increment (1-origin screen) */
  453.         col++;
  454.         line++;
  455.         break;
  456.         case '%':                /* %%=% literally */
  457.         *bufp++='%';
  458.         break;
  459.         case 'n':                /* magic DM2500 code */
  460.         line ^= 0140;
  461.         col ^= 0140;
  462.         break;
  463.         case 'B':                /* bcd encoding */
  464.         line = line/10<<4+line%10;
  465.         col = col/10<<4+col%10;
  466.         break;
  467.         case 'D':                /* magic Delta Data code */
  468.         line = line-2*(line&15);
  469.         col = col-2*(col&15);
  470.         break;
  471.         default:                /* Unknown escape */
  472.         return "OOPS";
  473.         }
  474.     }
  475.     }
  476.  
  477.     if (addup)                    /* add upline */
  478.     if (UP) {
  479.         ptr=UP;
  480.         while (isdigit(*ptr) || *ptr == '.')
  481.         ptr++;
  482.         if (*ptr == '*')
  483.         ptr++;
  484.         while (*ptr)
  485.         *bufp++ = *ptr++;
  486.     }
  487.  
  488.     if (addbak)                    /* add backspace */
  489.     if (BC) {
  490.         ptr=BC;
  491.         while (isdigit(*ptr) || *ptr == '.')
  492.         ptr++;
  493.         if (*ptr == '*')
  494.         ptr++;
  495.         while (*ptr)
  496.         *bufp++ = *ptr++;
  497.     }
  498.     else
  499.         *bufp++='\b';
  500.  
  501.     *bufp = 0;
  502.  
  503.     return(buffer);
  504. }
  505.  
  506. /*
  507.  * Module: tputs
  508.  *
  509.  * Purpose: decode padding information
  510.  *
  511.  * Calling conventions: cp = string to be padded, affcnt = # of items affected
  512.  *    (lines, characters, whatever), outc = routine to output 1 character.
  513.  *
  514.  * Returned values: none
  515.  *
  516.  * Notes
  517.  *    cp has padding information ahead of it, in the form
  518.  *  nnnTEXT or nnn*TEXT. nnn is the number of milliseconds to delay,
  519.  *  and may be a decimal (nnn.mmm). If the asterisk is given, then
  520.  *  the delay is multiplied by afcnt. The delay is produced by outputting
  521.  *  a number of nulls (or other padding char) after printing the
  522.  *  TEXT.
  523.  *
  524.  */
  525.  
  526. long _bauds[16]={
  527.     0,    50, 75,    110,
  528.     134,    150,    200,    300,
  529.     600,    1200,   1800,   2400,
  530.     4800,   9600,   19200,  19200 };
  531.  
  532. tputs(cp, affcnt, outc)
  533.     char *cp;                /* string to print */
  534.     int affcnt;                /* Number of lines affected */
  535.     void (*outc) __ARGS((unsigned int));/* routine to output 1 character */
  536. {
  537.     long    frac,            /* 10^(#digits after decimal point) */
  538.     counter,            /* digits */
  539.     atol __ARGS((const char *));
  540.  
  541.     if (isdigit(*cp)) {
  542.     counter = 0;
  543.     frac = 1000;
  544.     while (isdigit(*cp))
  545.         counter = counter * 10L + (long)(*cp++ - '0');
  546.     if (*cp == '.')
  547.         while (isdigit(*++cp)) {
  548.         counter = counter * 10L + (long)(*cp++ - '0');
  549.         frac = frac * 10;
  550.         }
  551.     if (*cp!='*') {            /* multiply by affected lines */
  552.         if (affcnt>1) affcnt = 1;
  553.     }
  554.     else
  555.         cp++;
  556.  
  557.     /* Calculate number of characters for padding counter/frac ms delay */
  558.     if (ospeed)
  559.         counter = (counter * _bauds[ospeed] * (long)affcnt) / frac;
  560.  
  561.     while (*cp)            /* output string */
  562.         (*outc)(*cp++);
  563.     if (ospeed)
  564.         while (counter--)        /* followed by pad characters */
  565.         (*outc)(PC);
  566.     }
  567.     else
  568.     while (*cp)
  569.         (*outc)(*cp++);
  570.     return 0;
  571. }
  572.  
  573. /*
  574.  * Module: tutil.c
  575.  *
  576.  * Purpose: Utility routines for TERMLIB functions.
  577.  *
  578.  */
  579.     static int
  580. _match(s1, s2)        /* returns length of text common to s1 and s2 */
  581.     char *s1, *s2;
  582. {
  583.     int i = 0;
  584.  
  585.     while (s1[i] && s1[i] == s2[i])
  586.     i++;
  587.  
  588.     return i;
  589. }
  590.  
  591. /*
  592.  * finds next c in s that's a member of set, returns pointer
  593.  */
  594.     static char *
  595. _find(s, set)
  596.     char *s, *set;
  597. {
  598.     for(; *s; s++)
  599.     {
  600.     char    *ptr = set;
  601.  
  602.     while (*ptr && *s != *ptr)
  603.         ptr++;
  604.  
  605.     if (*ptr)
  606.         return s;
  607.     }
  608.  
  609.     return s;
  610. }
  611.  
  612. /*
  613.  * add val to buf according to format fmt
  614.  */
  615.     static char *
  616. _addfmt(buf, fmt, val)
  617.     char *buf, *fmt;
  618.     int val;
  619. {
  620.     sprintf(buf, fmt, val);
  621.     while (*buf)
  622.     buf++;
  623.     return buf;
  624. }
  625.